import * as crypto from 'crypto-js'

interface ByteGeneratorParams {
	serverSeed: string
	clientSeed: string
	nonce: number
	cursor: number
}

export function* byteGenerator({
	serverSeed,
	clientSeed,
	nonce,
	cursor
}: ByteGeneratorParams): Generator<number> {
	let currentRound = Math.floor(cursor / 32)
	let currentRoundCursor = cursor % 32

	while (true) {
		const hmac = crypto.HmacSHA256(`${clientSeed}:${nonce}:${currentRound}`, serverSeed)
		const hmacHex = hmac.toString(crypto.enc.Hex)

		// Convert the hex string into an array of bytes (numbers)
		const byteArray = []
		for (let i = 0; i < hmacHex.length; i += 2) {
			byteArray.push(parseInt(hmacHex.substr(i, 2), 16))
		}

		while (currentRoundCursor < 32) {
			yield byteArray[currentRoundCursor]
			currentRoundCursor += 1
		}
		currentRoundCursor = 0
		currentRound += 1
	}
}

export function generateRandomHexString(length: number): string {
	const randomBytesValue = crypto.lib.WordArray.random(length / 2)
	return randomBytesValue.toString(crypto.enc.Hex)
}

export function calculateHash(inputString: string): string {
	return crypto.SHA256(inputString).toString(crypto.enc.Hex)
}

export function calculateResult(array: number[], factor: number): number {
	let decimalResult = 0
	for (let idx = 0; idx < array.length; idx++) {
		decimalResult += array[idx] / Math.pow(256, idx + 1)
	}
	return decimalResult * factor
}

/**
 *  赌场种子转换为字节-前端展示公开计算过程使用
 * @param {string} serverSeed - 服务端种子
 * @param {string} clientSeed - 客户端种子
 * @param {number} nonce - 随机数
 * @param {number} groups - 分组数
 */
export function casinoSeedToBytes(
	serverSeed: string,
	clientSeed: string,
	nonce: number,
	groups: number
): Record<string, number[]> {
	const bytesGroups = getBytesGroups(serverSeed, clientSeed, nonce, groups, 32)
	const dicBytes: Record<string, number[]> = {}
	for (let i = 0; i < groups; i++) {
		dicBytes[`HMAC_SHA256(1,1:${nonce}:${i})`] = bytesGroups[i]
	}
	return dicBytes
}

/**
 * 字节分组每4个为1组，分指定组
 * @param {string} serverSeed - 服务端种子
 * @param {string} clientSeed - 客户端种子
 * @param {number} nonce - 随机数
 * @param {number} groups - 分组数
 * @param {number} bytesLength - 每组字节数
 */
export function getBytesGroups(
	serverSeed: string,
	clientSeed: string,
	nonce: number,
	groups: number,
	bytesLength: number
): number[][] {
	const generator = byteGenerator({ serverSeed, clientSeed, nonce, cursor: 0 })
	const bytes: number[][] = []
	for (let i = 0; i < groups; i++) {
		const array: number[] = []
		for (let j = 0; j < bytesLength; j++) {
			const nextValue = generator.next().value
			if (nextValue !== undefined) {
				array.push(nextValue)
			}
		}
		bytes.push(array)
	}
	return bytes
}

interface FloatsGeneratorParams {
	serverSeed: string
	clientSeed: string
	nonce: number
}

export function* floatsGenerator({
	serverSeed,
	clientSeed,
	nonce
}: FloatsGeneratorParams): Generator<number> {
	const byteRng = byteGenerator({ serverSeed, clientSeed, nonce, cursor: 0 })

	while (true) {
		const bytes = Array(4)
			.fill(0)
			.map(() => byteRng.next().value || 0)
		const float = bytes.reduce((result, value, i) => {
			const divider = Math.pow(256, i + 1)
			const partialResult = value / divider

			return result + partialResult
		}, 0)

		yield float
	}
}
